package br.com.sgpv2.controler.movimentacao;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import br.com.sgpv2.controler.NegocioExeception;
import br.com.sgpv2.controler.SGPController;
import br.com.sgpv2.entity.evento.Evento;
import br.com.sgpv2.entity.evento.TipoEventoEnum;
import br.com.sgpv2.entity.folha.Folha;
import br.com.sgpv2.entity.folha.StatusFolhaEnum;
import br.com.sgpv2.entity.movimentacao.MesEnum;
import br.com.sgpv2.entity.movimentacao.Movimentacao;
import br.com.sgpv2.entity.movimentacao.MovimentacaoDTO;
import br.com.sgpv2.entity.movimentacao.ValoresEvento;
import br.com.sgpv2.entity.pessoa.Contrato;
import br.com.sgpv2.entity.pessoa.Pessoa;
import br.com.sgpv2.service.contrato.ContratoService;
import br.com.sgpv2.service.evento.EventoService;
import br.com.sgpv2.service.folha.FolhaService;
import br.com.sgpv2.service.movimentacao.MovimentacaoService;
import br.com.sgpv2.service.valoresevento.ValoresEventoService;

/**
 * Handles requests for the application /movimentacoes.
 */
@Controller
public class MovimentacaoController extends SGPController {

	@Autowired
	private MovimentacaoService movimentacaoService;
	@Autowired
	private EventoService eventoService;
	@Autowired
	private ContratoService contratoService;
	@Autowired
	private ValoresEventoService valoresEventoService;
	@Autowired
	private FolhaService folhaService;
	
	@RequestMapping(value = "/movimentacao/pre_incluir", method = RequestMethod.GET)
	public String preIncluir(Model model)
			throws Exception {
		
		model.addAttribute("movimentacao", new Movimentacao());
		model.addAttribute("mes", MesEnum.values());
		model.addAttribute("exibirCombo", true);
		return "movimentacao_pre_incluir";
	}
	
	@RequestMapping(value = "/movimentacao/pre_incluir/{mes}/{ano}", method = RequestMethod.GET)
	public String preIncluirMesAno(@PathVariable Integer mes, @PathVariable Integer ano, Model model)
			throws Exception {
		
		Movimentacao movimentacao = new Movimentacao();
		movimentacao.setMes(mes);
		movimentacao.setAno(ano);
		
		model.addAttribute("exibirCombo", false);
		model.addAttribute("movimentacao", movimentacao);
		return "movimentacao_pre_incluir";
	}
	
	@RequestMapping(value = "/movimentacao/incluir", method = RequestMethod.POST)
	public String incluir(@ModelAttribute("movimentacao") Movimentacao movimentacao, Model model) throws NegocioExeception {
		
		movimentacaoService.validarPreIncluir(movimentacao);
		configurarModel(movimentacao, null, null, null, model);
		return "movimentacao_manter";
	}
	
	@ExceptionHandler(NegocioExeception.class)
	public ModelAndView handleNegocioException(NegocioExeception ex) {
		 
		ModelAndView model = new ModelAndView("movimentacao_pre_incluir");
		model.addObject("errorMessage", ex.getMessage());
		Movimentacao movimentacao = new Movimentacao();
		movimentacao.setContrato(new Contrato());
		movimentacao.getContrato().setPessoa(new Pessoa());
		model.addObject("movimentacao", movimentacao);
		return model;
	}
	
	@RequestMapping(value = "/movimentacao/detalhar/{mes}/{ano}", method = RequestMethod.GET)
	public String movimentaocaoDetalhar(@PathVariable Integer mes, @PathVariable Integer ano, Model model) throws Exception {
		
		List<MovimentacaoDTO> movimentacoes = movimentacaoService.consultarPorPeriodo(mes, ano);
		configurarPaginacao(movimentacoes, model);
		model.addAttribute("mes", mes);
		model.addAttribute("ano", ano);
		model.addAttribute("movimentacoes", getPagedListHolder().getPageList());
		if(!movimentacoes.isEmpty()){
			model.addAttribute("folha", movimentacoes.get(0).getFolha());
		}else{
			model.addAttribute("folha", new Folha());
		}
		return "movimentacoes_mes_ano";
	}
	
	@RequestMapping(value = "/movimentacao/voltar", method = RequestMethod.GET)
	public String voltar(Model model, HttpServletRequest request){
	    return "redirect:/..";
	}
	
	
	@RequestMapping(value = "/movimentacao/alterar/{pk}", method = RequestMethod.GET)
	public String alterar(@PathVariable Integer pk, Model model) throws Exception {
		configurarModelAlterar(movimentacaoService.buscar(pk), null, null, null, model);
		return "movimentacao_manter";
	}
	
	@RequestMapping(value = "/movimentacao/addEvento", method = RequestMethod.POST)
	public String addEvento(
			@ModelAttribute("movimentacao") Movimentacao movimentacao,
			@RequestParam(required = false) Integer idEvento,
			@RequestParam(required = false) String valorEvento, 
			@RequestParam(required = false) String idsValoresEventoRemover,
			@RequestParam(required = false) Integer idEventoRemover,
			@RequestParam(required = false) Integer idValorEventoRemover,Model model)
			throws NegocioExeception {

		List<ValoresEvento> valoresEventoTemporarios = new ArrayList<ValoresEvento>(movimentacao.getValoresEvento());
		movimentacao = configurarMovimentacao(movimentacao);
		
		removerValoresEvento(idEventoRemover, idValorEventoRemover, idsValoresEventoRemover, movimentacao, valoresEventoTemporarios, model);
		
		configurarModel(movimentacao, idEvento, valorEvento, valoresEventoTemporarios,  model);
		
		
		return "movimentacao_manter";
	}
	
	private Movimentacao configurarMovimentacao(Movimentacao movimentacao) throws NegocioExeception {
		
		if (movimentacao.getId() != 0) {
			movimentacao = movimentacaoService.buscar(movimentacao.getId());
		} else {
			movimentacao.setContrato(contratoService.buscar(movimentacao.getContrato().getId()));
			movimentacao.setValoresEvento(new ArrayList<ValoresEvento>());
		}
		
		return movimentacao;
	}
	
	private void removerValoresEvento(Integer idEvento, Integer idValorEvento,
			String idsValoresEventos, Movimentacao movimentacao,
			List<ValoresEvento> valoresEventoTemporarios, Model model) {

		if (idValorEvento != null && !idValorEvento.equals(0)) {
			idsValoresEventos += ";" + idValorEvento;
		} else if (idEvento != null && !idEvento.equals(0)){
			ValoresEvento valorEventoRemover = null;
			for (ValoresEvento valoresEvento : valoresEventoTemporarios) {
				if (valoresEvento.getEvento().getId() == idEvento) {
					valorEventoRemover = valoresEvento;
					break;
				}
			}
			valoresEventoTemporarios.remove(valorEventoRemover);
		}
		
		if (idsValoresEventos != null && !idsValoresEventos.trim().isEmpty()) {
			List<ValoresEvento> valoresRemover = new ArrayList<ValoresEvento>();
			for (String idAtual : idsValoresEventos.split(";")) {
				if (idAtual != null && !idAtual.trim().isEmpty()) {
					for (ValoresEvento valoresEvento : movimentacao
							.getValoresEvento()) {
						if (Integer.valueOf(idAtual).equals(valoresEvento.getId())) {
							valoresRemover.add(valoresEvento);
						}
					}
				}
			}
			if (!valoresRemover.isEmpty()) {
				movimentacao.getValoresEvento().removeAll(valoresRemover);
			}
		}

		model.addAttribute("idsValoresEventoRemover", idsValoresEventos);
	}
	
	@RequestMapping(value = "/movimentacao/salvar", method = RequestMethod.POST)
	public String salvarMovimentacao(
			@ModelAttribute("movimentacao") Movimentacao movimentacao,
			@RequestParam(required = false) String idsValoresEventoRemover,
			Model model)
			throws NegocioExeception {

		List<ValoresEvento> valoresEventoTemporarios = new ArrayList<ValoresEvento>(movimentacao.getValoresEvento());
		
		movimentacao = configurarMovimentacao(movimentacao);
		
		removerValoresEvento(null, null, idsValoresEventoRemover, movimentacao, valoresEventoTemporarios, model);
		
		for (ValoresEvento valoresEvento : valoresEventoTemporarios) {
			valoresEvento.setEvento(eventoService.buscar(valoresEvento.getEvento().getId()));
			valoresEvento.setMovimentacao(movimentacao);
		}
		movimentacao.getValoresEvento().addAll(valoresEventoTemporarios);
		movimentacaoService.calcularValoresTotalMovimentacao(movimentacao);
		
		movimentacao.setData(new Date());
		
		Folha folha = folhaService.buscarPorMesAno(movimentacao.getMes(), movimentacao.getAno());
		
		if(folha != null){
			movimentacao.setFolha(folha);
		}else{
			folha = new Folha();
			folha.setAno(movimentacao.getAno());
			folha.setMes(movimentacao.getMes());
			folha.setStatus(StatusFolhaEnum.ABERTA);
			folhaService.salvar(folha);
			movimentacao.setFolha(folha);
		}
		
		if (movimentacao.getId() != 0) {
			movimentacaoService.alterar(movimentacao);
		} else {
			movimentacaoService.salvar(movimentacao);
		}
		
		return "redirect:../folhas";
	}
	
	public void configurarValoresEvento(Integer idEvento, String valorEvento, Movimentacao movimentacao, List<ValoresEvento> valoresEventoTemporarios, Model model) throws NegocioExeception {
		
		if (valoresEventoTemporarios == null) {
			valoresEventoTemporarios = new ArrayList<ValoresEvento>();
		}
		
		for (ValoresEvento valoresEvento : valoresEventoTemporarios) {
			valoresEvento.setEvento(eventoService.buscar(valoresEvento.getEvento().getId()));
		}
		
		if (idEvento != null && !idEvento.equals(0)) {
			
			ValoresEvento valoresEvento = new ValoresEvento();
			valoresEvento.setEvento(eventoService.buscar(idEvento));
			Double valor = transformStringToDouble(valorEvento);
			if (valor != null) {
				valoresEvento.setValor(BigDecimal.valueOf(valor));
			}
			valoresEventoTemporarios.add(valoresEvento);
		}
		model.addAttribute("valoresEventoTemporarios", valoresEventoTemporarios);
		movimentacao.getValoresEvento().addAll(valoresEventoTemporarios);
		model.addAttribute("valoresEventos", movimentacao.getValoresEvento());
	}
	
	public void configurarValoresEventoAlterar(Integer idEvento, String valorEvento, Movimentacao movimentacao, List<ValoresEvento> valoresEventoTemporarios, Model model) throws NegocioExeception {
		
		if (valoresEventoTemporarios == null) {
			valoresEventoTemporarios = new ArrayList<ValoresEvento>();
		}
		
		for (ValoresEvento valoresEvento : valoresEventoTemporarios) {
			valoresEvento.setEvento(eventoService.buscar(valoresEvento.getEvento().getId()));
		}
		
		if (idEvento != null && !idEvento.equals(0)) {
			
			ValoresEvento valoresEvento = new ValoresEvento();
			valoresEvento.setEvento(eventoService.buscar(idEvento));
			Double valor = transformStringToDouble(valorEvento);
			if (valor != null) {
				valoresEvento.setValor(BigDecimal.valueOf(valor));
			}
			valoresEventoTemporarios.add(valoresEvento);
		}
		
		model.addAttribute("valoresEventoTemporarios", valoresEventoTemporarios);
		List<ValoresEvento> valoresBanco = new ArrayList<ValoresEvento>(); 
		
		for (ValoresEvento valoresEvento : movimentacao.getValoresEvento()) {
			ValoresEvento valorBanco = valoresEventoService.buscar(valoresEvento.getId());
			
			if(TipoEventoEnum.PROVENTO.equals(valorBanco.getEvento().getTipoEventoEnum())){
				valorBanco.getEvento().setValorProvento(valorBanco.getValor());
			}else{
				valorBanco.getEvento().setValorDesconto(valorBanco.getValor());
			}			
			valoresBanco.add(valorBanco);
		}
		
		movimentacao.setValoresEvento(valoresBanco);
		model.addAttribute("valoresEventos", movimentacao.getValoresEvento());
	}
	
	private void configurarModel(Movimentacao movimentacao, Integer idEvento, String valorEvento, List<ValoresEvento> valoresEventoTemporarios, Model model) throws NegocioExeception {
		model.addAttribute("movimentacao", movimentacao);

		configurarValoresEvento(idEvento, valorEvento, movimentacao, valoresEventoTemporarios, model);
		movimentacaoService.calcularValoresTotalMovimentacao(movimentacao);
		model.addAttribute("eventos", eventoService.listar());
	}
	
	private void configurarModelAlterar(Movimentacao movimentacao, Integer idEvento, String valorEvento, List<ValoresEvento> valoresEventoTemporarios, Model model) throws NegocioExeception {
		model.addAttribute("movimentacao", movimentacao);

		configurarValoresEventoAlterar(idEvento, valorEvento, movimentacao, valoresEventoTemporarios, model);
		
		model.addAttribute("eventos", eventoService.listar());
	}
	
	@ResponseBody
	@RequestMapping(value = "/movimentacao/buscar-evento/{codigoEvento}", method = RequestMethod.GET)
	public boolean buscarEvento(@PathVariable Integer codigoEvento, Model model)
			throws NumberFormatException, NegocioExeception {
		Evento evento = eventoService.buscar(codigoEvento);
		return evento.getIsEventoPercentual();
	}
	
	@ResponseBody
	@RequestMapping(value = "/movimentacao/buscar-contrato/{matriculaContrato}", method = RequestMethod.GET)
	public String buscarContrato(
			@PathVariable String matriculaContrato, Model model)
			throws NumberFormatException, NegocioExeception {
		Contrato contrato = contratoService
				.buscarPorMatricula(matriculaContrato);

		String retorno = null;
		
		if (contrato != null) {
			retorno = contrato.getPessoa().getNome();
		}

		return retorno;
	}
	
	@ResponseBody
	@RequestMapping(value = "/movimentacao/paginacao/{acao}", method = RequestMethod.GET)
	public ModelAndView paginacao(@PathVariable String acao, Model model) throws Exception {		
		navegarPaginacao(acao, model);
		model.addAttribute("movimentacoes", getPagedListHolder().getPageList());
		return new ModelAndView("movimentacao.lista.mes.ano");
	}
}
